﻿using System;
using System.Collections.Generic;
using UnityEngine;

public class VertexBuffer
{
    public readonly List<Vector3> vertices;
    public readonly List<Color32> colors;
    public readonly List<int> triangles;

    public Color32 vertexColor;

    static Stack<VertexBuffer> _pool = new Stack<VertexBuffer>();

    public static VertexBuffer Begin()
    {
        if (_pool.Count > 0)
        {
            VertexBuffer inst = _pool.Pop();
            inst.Clear();
            return inst;
        }
        else
            return new VertexBuffer();
    }

    public void End()
    {
        _pool.Push(this);
    }

    public int currentVertCount
    {
        get { return vertices.Count; }
    }

    private VertexBuffer()
    {
        vertices = new List<Vector3>();
        colors = new List<Color32>();
        triangles = new List<int>();
    }


    public void Clear()
    {
        vertices.Clear();
        colors.Clear();
        triangles.Clear();
    }

    private void AddVert(Vector3 position)
    {
        AddVert(position, vertexColor);
    }

    private void AddVert(Vector3 position, Color32 color)
    {
        vertices.Add(position);
        colors.Add(color);
    }

    public void AddQuad(Rect vertRect)
    {
        AddQuad(vertRect, vertexColor);
    }

    public void AddQuad(Rect vertRect, Color32 color)
    {
        AddVert(new Vector3(vertRect.xMin, vertRect.yMax, 0f), color);
        AddVert(new Vector3(vertRect.xMin, vertRect.yMin, 0f), color);
        AddVert(new Vector3(vertRect.xMax, vertRect.yMin, 0f), color);
        AddVert(new Vector3(vertRect.xMax, vertRect.yMax, 0f), color);
        AddQuadIndics();
    }

    public void AddRect(Rect vertRect)
    {
        AddRect(vertRect, vertexColor);
    }

    public void AddRect(Rect vertRect, Color32 color)
    {
        Vector3 a = new Vector3(vertRect.xMin, vertRect.yMax, 0f);
        Vector3 b = new Vector3(vertRect.xMin, vertRect.yMin, 0f);
        Vector3 c = new Vector3(vertRect.xMax, vertRect.yMin, 0f);
        Vector3 d = new Vector3(vertRect.xMax, vertRect.yMax, 0f);

        AddLine(a, b, Vector3.forward);
        AddLine(b, c, Vector3.forward);
        AddLine(c, d, Vector3.forward);
        AddLine(d, a, Vector3.forward);
    }

    public void AddLine(Vector3 a, Vector3 b, Vector3 n)
    {
        AddLine(a, b, n, vertexColor);
    }

    public void AddLine(Vector3 a, Vector3 b, Vector3 n, Color32 color)
    {
        Vector3 l = Vector3.Cross(b - a, n);
        l = l.normalized * 1 / 2;
        Vector3 v0 = a + l;
        Vector3 v1 = a - l;
        Vector3 v2 = b - l;
        Vector3 v3 = b + l;

        AddVert(v0, color);
        AddVert(v1, color);
        AddVert(v2, color);
        AddVert(v3, color);

        AddQuadIndics();
    }

    public void AddTriangle(Vector3 v0, Vector3 v1, Vector3 v2)
    {
        AddTriangle(v0, v1, v2, vertexColor);
    }

    public void AddTriangle(Vector3 v0, Vector3 v1, Vector3 v2, Color32 color)
    {
        AddVert(v0, color);
        AddVert(v1, color);
        AddVert(v2, color);
        AddTriangleIndics();
    }

    private void AddTriangleIndics()
    {
        int i = vertices.Count - 3;
        AddTriangleIndics(i, i + 1, i + 2);
    }

    private void AddTriangleIndics(int idx0, int idx1, int idx2)
    {
        triangles.Add(idx0);
        triangles.Add(idx1);
        triangles.Add(idx2);
    }

    private void AddQuadIndics()
    {
        int i = vertices.Count - 4;
        AddTriangleIndics(i, i + 1, i + 2);
        AddTriangleIndics(i + 2, i + 3, i);
    }

    public void AddCycle(Vector3 center, float radius)
    {
        AddCycle(center, radius, vertexColor);
    }

    public void AddCycle(Vector3 center, float radius, Color color)
    {
        float m_Theta = 0.1f;
        // 设置矩阵
        // 绘制圆环
        Vector3 beginPoint = Vector3.zero;
        Vector3 firstPoint = Vector3.zero;
        for (float theta = 0; theta < 2 * Mathf.PI; theta += m_Theta)
        {
            float x = radius * Mathf.Cos(theta);
            float y = radius * Mathf.Sin(theta);
            Vector3 endPoint = new Vector3(center.x + x, center.y + y, center.z);
            if (theta == 0)
            {
                firstPoint = endPoint;
            }
            else
            {
                AddLine(beginPoint, endPoint, Vector3.forward, color);
            }

            beginPoint = endPoint;
        }

        AddLine(firstPoint, beginPoint, Vector3.forward, color);
    }

    public void AddEllipse(Vector3 center, float radius, float radian)
    {
        AddEllipse(center, radius, radian, vertexColor);
    }
    
    public void AddEllipse(Vector3 center, float radius, Color color)
    {
        AddEllipse(center, radius, 2 * Mathf.PI, color);
    }
    
    public void AddEllipse(Vector3 center, float radius, float radian, Color color)
    {
        float m_Theta = 0.1f;
        // 设置矩阵
        // 绘制圆环
        Vector3 beginPoint = Vector3.zero;
        Vector3 firstPoint = Vector3.zero;
        for (float theta = 0; theta < radian; theta += m_Theta)
        {
            float x = radius * Mathf.Cos(theta);
            float y = radius * Mathf.Sin(theta);
            Vector3 endPoint = new Vector3(center.x + x, center.y + y, center.z);
            if (theta == 0)
            {
                firstPoint = endPoint;
            }
            else
            {
                AddTriangle(beginPoint, endPoint, center, color);
            }

            beginPoint = endPoint;
        }

        if (Math.Abs(radian - Math.PI * 2) < 0.001f)
        {
            AddTriangle(firstPoint, beginPoint, center, color);
        }
    }
    
    public void Append(VertexBuffer vb)
    {
        int len = vertices.Count;
        vertices.AddRange(vb.vertices);
        colors.AddRange(vb.colors);
        if (len != 0)
        {
            int len1 = vb.triangles.Count;
            for (int i = 0; i < len1; i++)
                triangles.Add(vb.triangles[i] + len);
        }
        else
            triangles.AddRange(vb.triangles);
    }

    public void Insert(VertexBuffer vb)
    {
        vertices.InsertRange(0, vb.vertices);
        colors.InsertRange(0, vb.colors);
        int len = triangles.Count;
        if (len != 0)
        {
            int len1 = vb.vertices.Count;
            for (int i = 0; i < len; i++)
                triangles[i] += len1;
        }

        triangles.InsertRange(0, vb.triangles);
    }

    public Mesh ToMesh()
    {
        Mesh mesh = new Mesh();
        mesh.SetVertices(vertices);
        mesh.SetColors(colors);
        mesh.SetTriangles(triangles, 0);
        return mesh;
    }
}